package icu.zqyhdm.blog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import icu.zqyhdm.blog.constant.RedisConst;
import icu.zqyhdm.blog.entity.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import icu.zqyhdm.blog.mapper.*;
import icu.zqyhdm.blog.utils.PageUtil;
import icu.zqyhdm.blog.vo.*;
import icu.zqyhdm.exception.MyException;
import icu.zqyhdm.result.Result;
import icu.zqyhdm.result.ResultCodeEnum;
import icu.zqyhdm.blog.openFeign.CommonServiceFeignClient;
import icu.zqyhdm.blog.service.*;
import icu.zqyhdm.helper.JwtHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author lifu
 * @Date 2021/6/22 21:18
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TypeMapper typeMapper;
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private ArticleTagMapper articleTagMapper;
    @Autowired
    private ArticleTagService articleTagService;
    @Autowired
    private CommentService commentService;
    @Autowired
    private CreateTimeService createTimeService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CommonServiceFeignClient commonServiceFeignClient;

    //工具方法，文章需要查询的内容
    private QueryWrapper<Article> getArticleQueryWrapper(){
        QueryWrapper<Article> articleQueryWrapper = new QueryWrapper<Article>();
        //查询文章id、标题、描述、首图、作者id、浏览数、点赞数、类型、时间
        articleQueryWrapper.select("id","title","author_id","create_time","update_time","first_picture","type_id","description","top");
        return articleQueryWrapper;
    }

    //根据名称对文章进行模糊查询
    @Override
    @Cacheable(value = "blog:articlePage",keyGenerator = "keyGenerator")
    public Page<ArticleListVo> selectPageByName(Integer current, Integer limit, ArticleQueryVo articleQueryVo) {
        Page<Article> articlePage = new Page<>(current,limit);
        Page<ArticleListVo> emptyPage = new Page<>(current,limit);

        String title = articleQueryVo.getTitle();//文章标题
        String authorName = articleQueryVo.getAuthorName();//文章作者昵称
        String typeName = articleQueryVo.getTypeName();//文章类型名
        String tagName = articleQueryVo.getTagName();//文章标签名
        String createTimeBegin = articleQueryVo.getCreateTimeBegin();//文章创建起始时间
        String createTimeEnd = articleQueryVo.getCreateTimeEnd();//文章创建结束时间

        QueryWrapper<Article> articleQueryWrapper = getArticleQueryWrapper();
        //按时间降序排
        articleQueryWrapper.orderByDesc("create_time");
        //对条件值进行非空判断
        if(!StringUtils.isEmpty(title)) {
            articleQueryWrapper.like("title",title);
        }
        if(!StringUtils.isEmpty(authorName)) {
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.like("nick_name",authorName);
            List<User> userList = userMapper.selectList(userQueryWrapper);

            if(!userList.isEmpty()){
                List<Integer> userIdList = userList.stream().map(user -> {
                    return user.getId();
                }).collect(Collectors.toList());
                articleQueryWrapper.in("author_id",userIdList);
            }else {
                //返回一个空的页
                return emptyPage;
            }
        }
        if(!StringUtils.isEmpty(typeName)) {
            QueryWrapper<Type> typeQueryWrapper = new QueryWrapper<>();
            typeQueryWrapper.like("type_name",typeName);
            List<Type> typeList = typeMapper.selectList(typeQueryWrapper);
            if(!typeList.isEmpty()){
                List<Integer> typeIdList = typeList.stream().map(type -> {
                    return type.getId();
                }).collect(Collectors.toList());
                articleQueryWrapper.in("type_id",typeIdList);
            }else {
                //返回一个空的页
                return emptyPage;
            }
        }
        if(!StringUtils.isEmpty(tagName)) {
            //根据标签名查文章, 查询到对应的标签
            List<Tag> tagList = tagMapper.selectList(new QueryWrapper<Tag>().
                    like("tag_name",tagName));
            if(!tagList.isEmpty()){
                List<Integer> tagIdList = tagList.stream().map(tag -> {
                    return tag.getId();
                }).collect(Collectors.toList());
                QueryWrapper<ArticleTag> articleTagQueryWrapper = new QueryWrapper<>();
                articleTagQueryWrapper.in("tag_id",tagIdList);
                //一个标签会对应多个文章id
                List<ArticleTag> articleTagList = articleTagService.list(articleTagQueryWrapper);
                if(!articleTagList.isEmpty()){
                    List<Integer> articleIdList = articleTagList.stream().map(articleTag -> {
                        return articleTag.getArticleId();
                    }).collect(Collectors.toList());
                    articleQueryWrapper.in("id",articleIdList);
                }else {
                    //返回一个空的页
                    return emptyPage;
                }
            }else {
                //返回一个空的页
                return emptyPage;
            }
        }
        if(!StringUtils.isEmpty(createTimeBegin)) {
            articleQueryWrapper.ge("create_time",createTimeBegin);
        }
        if(!StringUtils.isEmpty(createTimeEnd)) {
            articleQueryWrapper.le("create_time",createTimeEnd);
        }
        //调用mapper的方法
        articlePage = baseMapper.selectPage(articlePage, articleQueryWrapper);
        Page<ArticleListVo> articleListVoPage = PageUtil.page(articlePage, ArticleListVo.class);
        //封装文章的其他参数信息
        List<ArticleListVo> records = articleListVoPage.getRecords().stream().map(articleListVo -> {
            return setArticleInfo(articleListVo);
        }).collect(Collectors.toList());
        articleListVoPage.setRecords(records);
        return articleListVoPage;
    }

    //根据id对文章进行精确查询
    @Override
    @Cacheable(value = "blog:articlePage",keyGenerator = "keyGenerator")
    public Page<ArticleListVo> selectPageById(Integer current, Integer limit, ArticleQueryIdVo articleQueryIdVo) {
        Page<Article> articlePage = new Page<>(current,limit);
        Page<ArticleListVo> emptyPage = new Page<>(current,limit);

        Integer authorId = articleQueryIdVo.getAuthorId();//作者id
        Integer typeId = articleQueryIdVo.getTypeId();
        Integer tagId = articleQueryIdVo.getTagId();
        QueryWrapper<Article> articleQueryWrapper = getArticleQueryWrapper();
        //按时间降序排
        articleQueryWrapper.orderByDesc("create_time");
        //对条件值进行非空判断
        if(authorId != null) {
            articleQueryWrapper.eq("author_id",authorId);
        }
        if(typeId != null) {
            articleQueryWrapper.eq("type_id",typeId);
        }
        if(tagId != null) {
            QueryWrapper<ArticleTag> articleTagQueryWrapper = new QueryWrapper<>();
            articleTagQueryWrapper.eq("tag_id",tagId);
            //一个标签会对应多个文章id
            List<ArticleTag> articleTagList = articleTagService.list(articleTagQueryWrapper);
            if(!articleTagList.isEmpty()){
                List<Integer> articleIdList = articleTagList.stream().map(articleTag -> {
                    return articleTag.getArticleId();
                }).collect(Collectors.toList());
                articleQueryWrapper.in("id",articleIdList);
            }else {
                //返回一个空的页
                return emptyPage;
            }
        }
        //调用mapper的方法
        Page<Article> pages = baseMapper.selectPage(articlePage, articleQueryWrapper);
        Page<ArticleListVo> articleListVoPage = PageUtil.page(articlePage, ArticleListVo.class);
        //封装文章的其他参数信息
        List<ArticleListVo> records = articleListVoPage.getRecords().stream().map(articleListVo -> {
            return setArticleInfo(articleListVo);
        }).collect(Collectors.toList());
        articleListVoPage.setRecords(records);
        return articleListVoPage;
    }
    //保存文章
    @Override
    @Transactional(rollbackFor=Exception.class)
    @Caching(evict = {@CacheEvict(value = "blog:articlePage",allEntries = true),
            @CacheEvict(value = "blog:articleDetail",allEntries = true),
            @CacheEvict(value = "blog:archive",allEntries = true),
            @CacheEvict(value = "blog:userInfo",allEntries = true)})
    public Integer saveArticle(String token, ArticleUploadVo articleUploadVo) {
        Article article = BeanUtil.copyProperties(articleUploadVo, Article.class);
        //设置作者
        article.setAuthorId(JwtHelper.getUserId(token));
        // 创建文章的标签
        List<ArticleTag> articleTagList = new ArrayList<>();
        try {
            baseMapper.insert(article); //insert后会返回id
            Integer articleId = article.getId();
            for(Integer tagId : articleUploadVo.getTagIdList()){
                ArticleTag articleTag = new ArticleTag();
                articleTag.setArticleId(articleId);
                articleTag.setTagId(tagId);
                articleTagList.add(articleTag);
            }
            articleTagService.saveBatch(articleTagList);
            //设置文章的初始浏览量是1，方便排序
            redisTemplate.opsForZSet().add(RedisConst.ARTICLE_VIEWS_COUNT,articleId,1D);
            return articleId;
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(ResultCodeEnum.NET_ERROR);
        }
    }

    //修改文章
    @Override
    @Transactional(rollbackFor=Exception.class)
    @Caching(evict = {@CacheEvict(value = "blog:articlePage",allEntries = true),
            @CacheEvict(value = "blog:articleDetail",allEntries = true),
            @CacheEvict(value = "blog:archive",allEntries = true)})
    public Integer updateArticle(String token, ArticleUploadVo articleUploadVo) {
        //用户的权限判断，非管理员和作者本人不能修改
        Integer userId = JwtHelper.getUserId(token);
//        // 获取文章的作者id
//        Article oldArticle = baseMapper.selectById(articleUploadVo.getId());
//        Integer authorId = oldArticle.getAuthorId();
//
//        Integer role = userMapper.selectById(userId).getRole();
//        if(!(authorId.equals(userId) || role.intValue() == 1)){
//            throw new MyException(ResultCodeEnum.AUTHORITY_ERROR);
//        }
        Article article = BeanUtil.copyProperties(articleUploadVo, Article.class);
        article.setAuthorId(userId);
        //事务
        try {
            List<Integer> newTagIdList = articleUploadVo.getTagIdList();
            if(newTagIdList == null || newTagIdList.isEmpty()){
                // 没有标签，状态为草稿
                article.setStatus(0);
                baseMapper.updateById(article);
            }else {
                //修改文章的标签信息
                List<ArticleTag> oldArticleTagList = articleTagService.getByArticleId(article.getId());
                if(oldArticleTagList != null && oldArticleTagList.isEmpty()){
                    // 标签不为空
                    List<Integer> oldTagIdList = oldArticleTagList.stream().map(oldArticleTag -> {
                        return oldArticleTag.getTagId();
                    }).collect(Collectors.toList());
                    // 先删除文章id和标签id的对应关系
                    QueryWrapper<ArticleTag> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("article_id",article.getId());
                    articleTagService.remove(queryWrapper);
                    // 再插入文章id和标签id的对应关系
                    List<ArticleTag> articleTagList = new ArrayList<>();
                    for (Integer tagId : newTagIdList){
                        ArticleTag articleTag = new ArticleTag();
                        articleTag.setArticleId(article.getId());
                        articleTag.setTagId(tagId);
                        articleTagList.add(articleTag);
                    }
                    articleTagService.saveBatch(articleTagList);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(ResultCodeEnum.NET_ERROR);
        }
        return articleUploadVo.getId();
    }

    //删除文章
    @Override
    @Transactional(rollbackFor=Exception.class)
    @Caching(evict = {@CacheEvict(value = "blog:articlePage",allEntries = true),
            @CacheEvict(value = "blog:articleDetail",allEntries = true),
            @CacheEvict(value = "blog:archive",allEntries = true),
            @CacheEvict(value = "blog:articleHot",allEntries = true),
            @CacheEvict(value = "blog:userInfo",allEntries = true)})
    public void deleteArticle(String token, Integer articleId) {
        //用户的权限判断，非作者本人不能修改
        Integer userId = JwtHelper.getUserId(token);
        Integer authorId = baseMapper.selectById(articleId).getAuthorId();
        Integer role = userMapper.selectById(userId).getRole();
        if(!(authorId.equals(userId) || role.intValue() == 1)){
            throw new MyException(ResultCodeEnum.AUTHORITY_ERROR);
        }
        //事务
        try {
            //删除文章
            baseMapper.deleteById(articleId);
            //删除文章和标签的对应关系
            QueryWrapper<ArticleTag> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("article_id",articleId);
            articleTagService.remove(queryWrapper);
            //删除文章的评论
            commentService.deleteCommentByArticleId(articleId);
            //删除redis的浏览量和点赞量
            redisTemplate.opsForZSet().remove(RedisConst.ARTICLE_VIEWS_COUNT,articleId);
            redisTemplate.opsForZSet().remove(RedisConst.ARTICLE_LIKE_COUNT,articleId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(ResultCodeEnum.NET_ERROR);
        }
    }

    //查询文章详情
    @Override
    @Cacheable(value = "blog:articleDetail",key = "#id")
    public ArticleDetailVo getArticleById(Integer id) {
        Article article = baseMapper.selectById(id);
        ArticleDetailVo articleDetailVo = BeanUtil.copyProperties(article, ArticleDetailVo.class);
        // 上一篇下一篇
        Article lastArticle = baseMapper.selectOne(new QueryWrapper<Article>()
                .select("id","title","first_picture","create_time")
                .lt("id",id)
                .orderByAsc("id")
                .last("LIMIT 1"));
        Article nextArticle = baseMapper.selectOne(new QueryWrapper<Article>()
                .select("id","title","first_picture","create_time")
                .gt("id",id)
                .orderByAsc("id")
                .last("LIMIT 1"));
        articleDetailVo.setLastArticle(BeanUtil.copyProperties(lastArticle,ArticleInfoVo.class));
        articleDetailVo.setNextArticle(BeanUtil.copyProperties(nextArticle,ArticleInfoVo.class));
        // 封装信息
        setArticleInfo(articleDetailVo);
        // 相关推荐文章,根据标签名
        List<TagVo> tagVoList = articleDetailVo.getTagVoList();
        if(!tagVoList.isEmpty()){
            // 得到标签名的集合
            List<String> tagNameList = tagVoList.stream().map(tag -> {
                return tag.getTagName();
                }).collect(Collectors.toList());
            // 查询到同标签名的所有标签（考虑到不同人创建的标签名会相同）
            List<Tag> tags = tagMapper.selectList(new QueryWrapper<Tag>()
                    .in("tag_name",tagNameList));
            // 查询到同标签名的所有标签id
            List<Integer> integers = tags.stream().map(tag -> {
                return tag.getId();
                }).collect(Collectors.toList());
            // 查询到所有文章id和标签id的对应
            List<ArticleTag> articleTagList = articleTagService.list(new QueryWrapper<ArticleTag>().in("tag_id",integers));
            List<Integer> articleIdList = articleTagList.stream().map(articleTag -> {
                return articleTag.getArticleId();
                }).collect(Collectors.toList());
            //移除文章自身
            articleIdList.remove(id);
            if(!articleIdList.isEmpty()){
                QueryWrapper<Article> articleQueryWrapper3 = new QueryWrapper<>();
                articleQueryWrapper3.select("id","title","first_picture","create_time");
                articleQueryWrapper3.in("id",articleIdList).orderByDesc("views").last("limit 3");
                List<Article> articleList = baseMapper.selectList(new QueryWrapper<Article>()
                        .select("id","title","first_picture","create_time")
                        .in("id",articleIdList)
                        .last("limit 3"));
                articleDetailVo.setRecommendArticleList(BeanUtil.copyToList(articleList, ArticleInfoVo.class));
            }else {
                articleDetailVo.setRecommendArticleList(Collections.emptyList());
            }
        }else {
            articleDetailVo.setRecommendArticleList(Collections.emptyList());
        }
        return articleDetailVo;
    }

    // 从redis查浏览数、点赞数动态数据
    @Override
    public ArticleDetailVo getDynamicData(ArticleDetailVo articleDetailVo) {
        //点赞和浏览量数据
        Double likeCount = redisTemplate.opsForZSet().score(RedisConst.ARTICLE_LIKE_COUNT, articleDetailVo.getId().toString());
        Double views = redisTemplate.opsForZSet().score(RedisConst.ARTICLE_VIEWS_COUNT, articleDetailVo.getId().toString());
        if(likeCount != null){
            articleDetailVo.setThumbs(likeCount.intValue());
        }
        if(views != null){
            articleDetailVo.setViews(views.intValue());
        }
        return articleDetailVo;
    }

    /**
     * 更新文章浏览量
     */
    @Async
    @Override
    public void updateArticleViews(HttpServletRequest request, Integer articleId) {
        HttpSession session = request.getSession();
        // 判断是否第一次访问
        Set<Integer> articleSet = (Set<Integer>) Optional.ofNullable(session.getAttribute(RedisConst.ARTICLE_SET)).orElse(new HashSet<>());
        //第一次访问，将文章id加入已浏览的文章列表
        if (!articleSet.contains(articleId)) {
            articleSet.add(articleId);
            session.setAttribute(RedisConst.ARTICLE_SET, articleSet);
        }
        // 浏览量+1
        // 用Zset存放文章浏览量
        redisTemplate.opsForZSet().incrementScore(RedisConst.ARTICLE_VIEWS_COUNT,articleId.toString(),1D);
    }

    //点赞
    @Async
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void likeArticle(String token, Integer articleId) {
        Integer userId = JwtHelper.getUserId(token);
        //事务
        try {
            // 判断用户是否点赞过
            if(redisTemplate.opsForSet().isMember(RedisConst.ARTICLE_USER_LIKE + userId.toString(),articleId.toString())){
                //点赞过，取消点赞，点赞数减一
                redisTemplate.opsForSet().remove(RedisConst.ARTICLE_USER_LIKE + userId.toString(),articleId.toString());
                redisTemplate.opsForZSet().incrementScore(RedisConst.ARTICLE_LIKE_COUNT,articleId.toString(),-1D);
            }else {
                //没点赞过，点赞，点赞数+1
                redisTemplate.opsForSet().add(RedisConst.ARTICLE_USER_LIKE + userId.toString(),articleId.toString());
                redisTemplate.opsForZSet().incrementScore(RedisConst.ARTICLE_LIKE_COUNT,articleId.toString(),1D);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //日期归档
    @Override
    public Page<CreateTimeVo> selectCreateTimeList(Integer current, Integer limit) {
        List<CreateTimeVo> createTimeVoList = createTimeService.selectCreateTimeList(current-1,limit.intValue());
        Page<CreateTimeVo> page = new Page<>();
        page.setRecords(createTimeVoList);
        page.setTotal(createTimeVoList.size());
        return page;
    }

    //热点文章，根据浏览量查
    @Override
    @Cacheable(value = "blog:articleHot",keyGenerator = "keyGenerator")
    public Page<ArticleHotVo> selectHotArticle(Integer current, Integer limit){
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet()
                .reverseRangeWithScores(RedisConst.ARTICLE_VIEWS_COUNT, 0, -1);
        List<ZSetOperations.TypedTuple<String>> typedTupleList = new ArrayList<>(typedTuples)
                .subList((current - 1) * limit, (current - 1) * limit + limit);
        //博客的id
        List<String> articleIdList = typedTupleList.stream().map(typedTuple -> {
            return typedTuple.getValue();
        }).collect(Collectors.toList());
        //根据id查询
        List<Article> articleList = baseMapper.selectList(new QueryWrapper<Article>()
                .select("id", "title", "first_picture", "create_time")
                .in("id", articleIdList));
        List<ArticleHotVo> articleHotVos = BeanUtil.copyToList(articleList, ArticleHotVo.class);
        for(int i = 0; i < limit; i++){
            Double score = typedTupleList.get(i).getScore();
            articleHotVos.get(i).setViews(score.intValue());
        }
        //封装
        Page<ArticleHotVo> pages = new Page<>(current,limit);
        pages.setRecords(articleHotVos).setTotal(typedTuples.size());
        return pages;
    }

    // 日期标题归档
    @Override
    @Cacheable(value = "blog:archive",keyGenerator = "keyGenerator")
    public Page<ArticleInfoVo> getArchiveList(Integer current, Integer limit) {
        Page<Article> articlePage = baseMapper.selectPage(new Page<Article>(current, limit),
                new QueryWrapper<Article>().select("id", "title", "create_time").orderByDesc("create_time"));
        Page<ArticleInfoVo> page = PageUtil.page(articlePage, ArticleInfoVo.class);
        return page;
    }

    //上传文件到阿里云oss
    @Override
    public String upload(String token, MultipartFile multipartFile,Integer articleId) {
        //生成一个唯一的文件名，以用户名id+文章名+文件名
        Integer userId = JwtHelper.getUserId(token);
        String fileName = userId.toString() + "/" + articleId.toString() +  "/" + multipartFile.getOriginalFilename();
        String resultString = commonServiceFeignClient.fileUpload(multipartFile, fileName);
        Result result = JSON.parseObject(resultString, Result.class);
        return result.getData().toString();
    }

    /**
     * 工具方法
     */
    //封装文章的其他信息：作者昵称，作者头像，类型名,标签列表
    private ArticleListVo setArticleInfo(ArticleListVo articleListVo){
        //作者信息
        Integer authorId = articleListVo.getAuthorId();
        User user = userMapper.selectById(authorId);
        articleListVo.setAuthorName(user.getNickName());
        articleListVo.setAuthorImg(user.getImg());
        //类型名
        Integer typeId = articleListVo.getTypeId();
        if(typeId != null){
            Type type = typeMapper.selectById(typeId);
            articleListVo.setTypeName(type.getTypeName());
        }
        //标签列表
        List<TagVo> tagVoList = getTagVoByArticleId(articleListVo.getId());
        articleListVo.setTagList(tagVoList);
        return articleListVo;
    }
    private ArticleDetailVo setArticleInfo(ArticleDetailVo articleDetailVo){
        //作者信息
        Integer authorId = articleDetailVo.getAuthorId();
        User user = userMapper.selectById(authorId);
        articleDetailVo.setAuthorName(user.getNickName());
        articleDetailVo.setAuthorImg(user.getImg());
        //类型名
        Integer typeId = articleDetailVo.getTypeId();
        if(typeId != null){
            Type type = typeMapper.selectById(typeId);
            articleDetailVo.setTypeName(type.getTypeName());
        }
        //标签列表
        List<TagVo> tagVoList = getTagVoByArticleId(articleDetailVo.getId());
        articleDetailVo.setTagVoList(tagVoList);
        return articleDetailVo;
    }
    // 根据文章id查标签
    private List<TagVo> getTagVoByArticleId(Integer articleId) {
        //根据文章id查对应的标签id列表
        List<ArticleTag> articleTagList = articleTagMapper.selectList(new QueryWrapper<ArticleTag>().eq("article_id",articleId));
        if(articleTagList != null && !articleTagList.isEmpty()){
            List<Integer> tagIdList = articleTagList.stream().map(articleTag -> {
                return articleTag.getTagId();
            }).collect(Collectors.toList());
            List<Tag> tagList = tagMapper.selectBatchIds(tagIdList);
            List<TagVo> tagVoList = BeanUtil.copyToList(tagList, TagVo.class);
            return tagVoList;
        }else {
            return new ArrayList<TagVo>();
        }
    }
}
